﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using System.Drawing;

namespace FeiYang
{

    public delegate bool 聊天事件处理_(挂机人物_ 人物, 聊天分类及内容_[] 内容);
    public delegate bool 切换频道_();

    public enum 聊天分类_
    {
        无_,
        系统喊话_,
        系统普通消息_,
        系统重要消息_,
        系统极品消息_,

        游戏功能消息_,
        喇叭消息_,
        公屏喊话_,
        附近消息_,
        行会消息_,
        组队消息_,
        私聊消息_,
    }

    public enum 聊天_
    {
        普通_,
        喊话_,
        行会_,
        组队_,
        私聊_,
    }

    public class 聊天分类及内容_
    {
        public 聊天分类及内容_(聊天分类_ 分类, string 内容)
        {
            this.分类 = 分类;
            this.内容 = 内容;
        }

        public 聊天分类_ 分类 { get; private set; }
        public string 内容 { get; private set; }
    }

    public class 聊天窗口_
    {
        public static Rectangle[] 有效聊天区域 = new Rectangle[]
        {
            Rectangle.FromLTRB(460,676,844,696),
            Rectangle.FromLTRB(460,697,844,717),
        };
        public static Point 打开聊天窗口点 = new Point(480, 716);
        public static Rectangle 输入窗口范围 = Rectangle.FromLTRB(120, 697, 272, 727);
        public static Rectangle 附近聊天探测范围 = Rectangle.FromLTRB(157, 50, 158, 616);
        public static Rectangle 附近聊天范围 = Rectangle.FromLTRB(154, 50, 492, 616);
        public 挂机人物_ 人物 { get; set; }

        public 线程_ 聊天监控线程 { get; set; }

        public 聊天事件处理_ 聊天事件处理;
        public 聊天窗口_(挂机人物_ 人物)
        {
            this.人物 = 人物;
            this.聊天监控线程 = new 线程_(识别聊天, false, "聊天监控线程", true);
        }

        public 聊天分类及内容_[] 上两条内容 { get; set; }
        public bool 识别聊天()
        {
            var 两行聊天内容 = 截取聊天内容();
            if (this.上两条内容 == null)
            {
                this.上两条内容 = 两行聊天内容;
            }
            else
            {
                var a0 = this.上两条内容[0];
                var b0 = 两行聊天内容[0];
                var a1 = this.上两条内容[1];
                var b1 = 两行聊天内容[1];
                if (a0.内容 == b0.内容 && a1.内容 == b1.内容)
                {
                    return true;
                }
                else
                {
                    this.上两条内容 = 两行聊天内容;
                }
            }
            聊天事件处理(人物, 两行聊天内容);
            return true;
        }

        public bool 聊天窗口是打开的()
        {
            return 其他_.循环判断(() => 图像_.查找图片(Properties.Resources.聊天窗口图标, 242, 636, 289, 682).X != -1);
        }

        public bool 打开聊天窗口()
        {
            if (!聊天窗口是打开的())
            {
                键鼠_.左键单击(打开聊天窗口点);
                return 聊天窗口是打开的();
            }
            return true;
        }
        public bool 切换到私聊频道()
        {
            打开聊天窗口();
            键鼠_.左键单击(75, 222);
            其他_.延迟(其他_.时长_1000);
            return true;
        }

        public bool 切换到普通频道()
        {
            打开聊天窗口();
            键鼠_.左键单击(75, 374);
            其他_.延迟(其他_.时长_1000);
            return true;
        }

        public bool 输出聊天(聊天_ 聊天, string 内容)
        {
            string 头;
            switch (聊天)
            {
                case 聊天_.喊话_:
                    头 = "!";
                    break;
                case 聊天_.行会_:
                    头 = "!~";
                    break;
                case 聊天_.组队_:
                    头 = "!!";
                    break;
                case 聊天_.私聊_:
                    头 = "/";
                    break;
                default:
                    头 = "";
                    break;
            }

            内容 = 头 + 内容;
            var 打开 = 打开聊天窗口();
            if (!打开) throw new Exception("打开聊天窗口失败");
            其他_.延迟(其他_.时长_600);
            键鼠_.左键单击(其他_.取中心(输入窗口范围));
            其他_.延迟(其他_.时长_600);
            键鼠_.输入文本(内容);
            其他_.延迟(其他_.时长_1000);
            键鼠_.左键单击(打开聊天窗口点);
            其他_.延迟(其他_.时长_400);
            关闭聊天窗口();
            return true;
        }

        public bool 关闭聊天窗口()
        {
            if (聊天窗口是打开的())
            {
                键鼠_.左键单击(521, 62);
                其他_.延迟(其他_.时长_600);
            }
            return true;
        }

        public string 详细探测最近的聊天内容(切换频道_ func)
        {
            func();
            var 白底 = 图像_.转换编译十六进制颜色字符串为BGR("FFFFFF");
            string ss = "";
            using (Bitmap parBitmap = new Bitmap(附近聊天范围.Width, 附近聊天范围.Height))
            using (Graphics g = Graphics.FromImage(parBitmap))
            {
                g.CopyFromScreen(new Point(附近聊天范围.Left, 附近聊天范围.Top), new Point(0, 0), new Size(附近聊天范围.Width, 附近聊天范围.Height));
                using (var img = parBitmap.ToImage<Bgr, byte>())
                using (Image<Bgr, byte> 探测列 = img.Copy(Rectangle.FromLTRB(0, 0, 1, 附近聊天范围.Height)))
                {
                    var p = 找到最后一个白色坐标(探测列);
                    if (p.X != -1)
                    {
                        var 行高 = 21;
                        var 行数 = p.Y / 行高;
                        var 余数 = p.Y % 行高;
                        if (余数 > 15) 行数++;
                        for (var i = 0; i < 行数; i++)
                        {
                            if (i == 行数 - 1 && 余数 > 15) 行高 = 余数;

                            int x = 0, x2 = 附近聊天范围.Width, y = p.Y - (i + 1) * 行高, y2 = p.Y - i * 行高;
                            var r = Rectangle.FromLTRB(x, y, x2, y2);
                            var s = "";
                            using (var h = img.Copy(r))
                            {
                                s = 图像_.识别文字(h);
                            }
                            s = s.Replace("：", ":");
                            ss = s + ss;
                            if (s.Contains(":"))
                            {
                                break;
                            }
                        }
                    }
                }
                关闭聊天窗口();
                return ss;
                Point 找到最后一个白色坐标(Image<Bgr, byte> t)
                {
                    for (var i = t.Rows - 1; i >= 0; i--)
                    {
                        for (var j = t.Cols - 1; j >= 0; j--)
                        {
                            var bgr = t[i, j];
                            if (比较颜色(bgr, 白底))
                            {
                                return new Point(j, i);
                            }
                        }
                    }
                    return new Point(-1, -1);
                }
            }

            bool 比较颜色(Bgr x, Bgr y, double 系数 = 60)
            {
                return Math.Abs(x.Blue - y.Blue) + Math.Abs(x.Green - y.Green) + Math.Abs(x.Red - y.Red) <= 系数;
            }
        }
        public 聊天分类及内容_[] 截取聊天内容()
        {
            using (Bitmap parBitmap = new Bitmap(有效聊天区域[0].Width, 有效聊天区域[0].Height * 2 + 1))
            using (Graphics g = Graphics.FromImage(parBitmap))
            {
                g.CopyFromScreen(new Point(有效聊天区域[0].Left, 有效聊天区域[0].Top), new Point(0, 0), new Size(有效聊天区域[0].Width, 有效聊天区域[0].Height * 2 + 1));
                using (var img = parBitmap.ToImage<Bgr, byte>())
                using (Image<Bgr, byte> 第一行 = img.Copy(Rectangle.FromLTRB(0, 0, 有效聊天区域[0].Width, 有效聊天区域[0].Height)))
                using (Image<Bgr, byte> 第二行 = img.Copy(Rectangle.FromLTRB(0, 有效聊天区域[0].Height + 1, 有效聊天区域[0].Width, 有效聊天区域[0].Height * 2 + 1)))
                {
                    var 第一行头部 = 第一行.Copy(Rectangle.FromLTRB(0, 0, 15, 第一行.Height));
                    var 第二行头部 = 第二行.Copy(Rectangle.FromLTRB(0, 0, 15, 第二行.Height));
                    var 第一行分类 = 根据颜色区分聊天分类(第一行头部);
                    var 第二行分类 = 根据颜色区分聊天分类(第二行头部);
                    var 第一行文本 = 图像_.识别文字(有效聊天区域[0]);
                    var 第二行文本 = 图像_.识别文字(有效聊天区域[1]);
                    return new 聊天分类及内容_[]
                      {
                              new 聊天分类及内容_(第一行分类, 第一行文本),
                              new 聊天分类及内容_(第二行分类, 第二行文本),
                      };
                }
            }

            聊天分类_ 根据颜色区分聊天分类(Image<Bgr, byte> t)
            {
                // 系统喊话
                var 红底 = 图像_.转换编译十六进制颜色字符串为BGR("0000DC");
                // 系统广播
                var 黄底 = 图像_.转换编译十六进制颜色字符串为BGR("00FFFF");
                // 公开喊话
                var 黄底2 = 图像_.转换编译十六进制颜色字符串为BGR("00EEFF");
                // 行会
                var 绿底 = 图像_.转换编译十六进制颜色字符串为BGR("005A00");
                var 蓝底 = 图像_.转换编译十六进制颜色字符串为BGR("FF0000");
                // 普通
                // 法力提示等
                // 私聊
                var 白底 = 图像_.转换编译十六进制颜色字符串为BGR("FFFFFF");
                // 喇叭广播
                var 橙底 = 图像_.转换编译十六进制颜色字符串为BGR("0077FF");
                // 粉底
                var 粉底 = 图像_.转换编译十六进制颜色字符串为BGR("FF00FF");
                // 灰底
                var 灰字 = 图像_.转换编译十六进制颜色字符串为BGR("779E9A");
                var 白字 = 图像_.转换编译十六进制颜色字符串为BGR("DEDEFA");
                var 红字 = 图像_.转换编译十六进制颜色字符串为BGR("0012FB");
                var 黑字 = 图像_.转换编译十六进制颜色字符串为BGR("2A2A2A");
                var 绿字 = 图像_.转换编译十六进制颜色字符串为BGR("0F640F");
                var 蓝字 = 图像_.转换编译十六进制颜色字符串为BGR("8F1E1E");
                var 私聊头绿字 = 图像_.转换编译十六进制颜色字符串为BGR("1DFF1D");

                double 红底数量 = 0, 黄底数量 = 0, 绿底数量 = 0, 白底数量 = 0, 蓝底数量 = 0,
                 橙底数量 = 0, 粉底数量 = 0, 黑字数量 = 0, 蓝字数量 = 0, 私聊头绿字数量 = 0, 灰底数量 = 0;

                double 总数 = t.Rows * t.Cols;
                for (var i = 0; i < t.Rows; i++)
                {
                    for (var j = 0; j < t.Cols; j++)
                    {
                        var bgr = t[i, j];
                        if (比较颜色(bgr, 红底))
                        {
                            红底数量++;
                        }
                        else if (比较颜色(bgr, 黄底))
                        {
                            黄底数量++;
                        }
                        else if (比较颜色(bgr, 私聊头绿字))
                        {
                            私聊头绿字数量++;
                        }
                        else if (比较颜色(bgr, 绿底))
                        {
                            绿底数量++;
                        }
                        else if (比较颜色(bgr, 白底))
                        {
                            白底数量++;
                        }
                        else if (比较颜色(bgr, 橙底))
                        {
                            橙底数量++;
                        }
                        else if (比较颜色(bgr, 粉底))
                        {
                            粉底数量++;
                        }
                        else if (比较颜色(bgr, 蓝底))
                        {
                            蓝底数量++;
                        }
                        else if (比较颜色(bgr, 黑字))
                        {
                            黑字数量++;
                        }
                        else if (比较颜色(bgr, 蓝字))
                        {
                            蓝字数量++;
                        }
                        else if (比较颜色(bgr, 灰字))
                        {
                            灰底数量++;
                        }
                    }
                }

                if (红底数量 / 总数 > 0.4 && 白底数量 > 5)
                {
                    // 红底 白字
                    return 聊天分类_.系统喊话_;
                }
                if (黄底数量 / 总数 > 0.4 && 红底数量 > 5)
                {
                    // 黄底红字
                    return 聊天分类_.系统重要消息_;
                }
                if (黄底数量 / 总数 > 0.4 && 黑字数量 > 5)
                {
                    // 黄底黑字
                    return 聊天分类_.公屏喊话_;
                }
                if (绿底数量 / 总数 > 0.4 && 白底数量 > 5)
                {
                    // 绿底白字
                    return 聊天分类_.行会消息_;
                }
                if (粉底数量 / 总数 > 0.4 && 白底数量 > 5)
                {
                    // 绿底白字
                    return 聊天分类_.喇叭消息_;
                }
                if (蓝底数量 / 总数 > 0.4 && 白底数量 > 5)
                {
                    // 蓝底白字
                    return 聊天分类_.系统普通消息_;
                }
                if (白底数量 / 总数 > 0.4 && 黑字数量 > 5)
                {
                    // 白底黑字
                    return 聊天分类_.附近消息_;
                }
                if (白底数量 / 总数 > 0.4 && 绿底数量 > 8)
                {
                    // 白底绿字
                    return 聊天分类_.游戏功能消息_;
                }
                if (白底数量 / 总数 > 0.4 && (蓝字数量 > 2 || 私聊头绿字数量 > 5))
                {
                    // 白底蓝字
                    return 聊天分类_.私聊消息_;
                }
                if (白底数量 / 总数 > 0.4 && 灰底数量 > 5)
                {
                    // 白底黑字
                    return 聊天分类_.组队消息_;
                }
                return 聊天分类_.无_;
            }

            bool 比较颜色(Bgr x, Bgr y, double 系数 = 60)
            {
                return Math.Abs(x.Blue - y.Blue)  + Math.Abs(x.Green - y.Green)  + Math.Abs(x.Red - y.Red) <= 系数;
            }
        }
    }
}
